//
//  UNStickyHeaderPagingContainerView.swift
//  Common
//
//  Created by 我骑着蜗牛走天下 on 2025/10/29.
//

import UIKit


/// StickyHeaderPagingView
///
/// 一个自定义复合视图组件，包含一个固定悬浮的顶部视图（`topView`）和一个横向分页滚动的`UIScrollView`（`scrollView`），
/// 每个分页内部包含一个垂直滚动的子滚动视图（如`UITableView`或`UICollectionView`）。
///
/// 该组件实现了以下功能：
/// - 顶部视图固定悬浮，随子滚动视图滚动联动上下移动，实现“吸顶”效果。
/// - 横向分页切换，支持多个子滚动视图分页展示。
/// - 多个子滚动视图联动同步滚动位置，保证顶部视图位置一致。
/// - 支持子滚动视图的`contentInset`自动调整，避免内容被顶部视图遮挡。
///
/// 使用方法：
/// 1. 创建并初始化`StickyHeaderPagingView`，设置其frame或使用Auto Layout布局。
/// 2. 通过`topHeight`属性设置顶部固定显示高度（通常是状态栏高度+导航栏高度）。
/// 3. 通过`topView`属性访问并自定义顶部视图内容。
/// 4. 创建多个子滚动视图（如`UITableView`或`UICollectionView`），
///    并赋值给`subScrollViews`属性，组件会自动布局并添加观察监听。
/// 5. 将`StickyHeaderPagingView`添加到你的视图层级中。
/// 6. 监听需要时，可通过代理或回调获取分页切换事件。
///
/// 注意事项：
/// - 子滚动视图必须是`UIScrollView`的子类，且支持`contentOffset`属性。
/// - 子滚动视图的`contentInsetAdjustmentBehavior`会被设置为`.never`，
///   如果你使用第三方刷新控件，请根据需求调整`contentInset`。
/// - 组件内部通过KVO监听子滚动视图的`contentOffset`，请避免外部重复监听导致冲突。
/// - 使用时应确保`topView.height`正确设置，否则悬浮效果可能异常。
///
/// 示例代码：
/// ```swift
/// let stickyPagingView = StickyHeaderPagingView(frame: view.bounds)
/// stickyPagingView.topHeight = 60 + UIApplication.shared.statusBarFrame.height
/// stickyPagingView.topView.backgroundColor = .systemBlue
///
/// let table1 = UITableView()
/// let table2 = UITableView()
/// stickyPagingView.subScrollViews = [table1, table2]
///
/// view.addSubview(stickyPagingView)
/// ```
///

@MainActor
public class UNStickyHeaderPagingContainerView: UIView,UIScrollViewDelegate{
    
    /// 头部固定显示高度
    var topHeight: CGFloat = 0//60 + StatusHeight
    
    /// 结束滚动
    public var endScrollingBlock: (_ page:Int) ->Void = {_ in}
    
    public var subScrollContentOffset: (_ offset: CGPoint) ->Void = {_ in }
    
    open var topView: UIView = UIView(){
        didSet{
            topView.frame = .init(x: 0, y: 0, width: self.width, height: topView.height)
            addSubview(topView)
        }
    }
    
    lazy var scrollView: UIScrollView = {
        let scroll = UIScrollView(frame: .init(x: 0, y: 0, width: self.width, height: self.height))
        scroll.prioritizeInteractivePopGestureRecognizer()
        scroll.backgroundColor = .white
        scroll.contentInsetAdjustmentBehavior = .never
        scroll.isPagingEnabled = true
        scroll.delegate = self
        return scroll
    }()
    
    open var subScrollViews: [UIScrollView] = [] {
        didSet {
            // 移除旧的观察者
            oldValue.forEach { table in
                table.removeObserver(self, forKeyPath: "contentOffset")
                table.removeFromSuperview()
            }
            
            // 添加新的 scrollViews 和观察者
            for table in subScrollViews {
                table.addObserver(self, forKeyPath: "contentOffset", options: [.new, .old], context: nil)
                table.contentInsetAdjustmentBehavior = .never
                scrollView.addSubview(table)
            }
            
            setNeedsLayout() // 标记需要布局，触发 layoutSubviews
        }
    }
    
    public func setCurrentIndex(index: Int){
        let offsetX = CGFloat(index) * scrollView.width
        if index < subScrollViews.count && scrollView.contentOffset.x != offsetX , let subScroll = subScrollViews[safe:index] {
            setOtherScrollViewOffset(subScroll)
            scrollView.setContentOffset(.init(x: offsetX, y: 0), animated: true)
        }
    }
    
    deinit{
        for table in subScrollViews {
            table.removeObserver(self, forKeyPath: "contentOffset")
        }
    }
    
    public override init(frame: CGRect) {
        super.init(frame: frame)
        
        addSubview(scrollView)
        
    }
    
    public override func layoutSubviews() {
        super.layoutSubviews()
        
        scrollView.frame = bounds
        topView.width = bounds.width
        
        let width = scrollView.bounds.width
        let height = scrollView.bounds.height
        
        // 根据当前 scrollView 尺寸设置 contentSize
        scrollView.contentSize = CGSize(width: width * CGFloat(subScrollViews.count), height: height)
        
        // 根据当前尺寸设置每个子滚动视图 frame 和 contentInset
        for (index, table) in subScrollViews.enumerated() {
            table.frame = CGRect(x: CGFloat(index) * width, y: 0, width: width, height: height)
            
            
            // 防止多次设置
            if table.contentInset.top == 0 {
                print("UIEdgeInsets")
                let insetTop = topView.height + table.contentInset.top
                // 设置 contentInset，确保内容不会被 topView 遮挡
                table.contentInset = UIEdgeInsets(top: insetTop , left: 0, bottom: 0, right: 0)
            }
        }
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        setOtherScrollViewOffset(scrollView)
    }
    
    // 手动拖拽滚动减速结束
    public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        endScrollingBlock( Int(scrollView.contentOffset.x / scrollView.width) )
    }
    
    func setOtherScrollViewOffset(_ scrollView: UIScrollView){
        let index = Int(scrollView.contentOffset.x / scrollView.width)
        
        // 获取当前显示的 子 滚动视图
        if let currentScrollView = subScrollViews[safe: index]{
            
            var offsetY = currentScrollView.contentOffset.y
            let insetTop = currentScrollView.contentInset.top
            let maxTop = topView.height - topHeight
            
            // 如果超过最大高度，设置为固定的最大显示高度
            if offsetY + insetTop > maxTop {
                offsetY = -topHeight
            }
            
            for subScrollView in subScrollViews {
                if subScrollView != currentScrollView {
                    subScrollView.setContentOffset(.init(x: 0, y: offsetY ), animated: false)
                }
            }
            
        }
    }
    
    
    // 实现观察回调
    public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "contentOffset", let _ = object as? UIScrollView {
            guard let _ = change?[.oldKey] as? CGPoint ,let newOffset = change?[.newKey] as? CGPoint else { return }
            
            DispatchQueue.main.async{ [weak self] in
                guard let self = self else { return }
                
                subScrollContentOffset(newOffset)
                
                let width = self.scrollView.width
                let offsetX = self.scrollView.contentOffset.x
                
                guard width > 0, !width.isNaN, !width.isInfinite, !offsetX.isNaN, !offsetX.isInfinite else {
                    print("Invalid scrollView width or contentOffset.x")
                    return
                }
                
                let index = Int( offsetX / width )
                
                if let currentScrollView = subScrollViews[safe: index] {
                    
                    let insetTop = currentScrollView.contentInset.top
                    
                    // 真实坐标从 当前y + 边距
                    let offsetY = newOffset.y + insetTop
                    // topView的最大 top， 从 topViewHeight 取反
                    let maxTop = topView.height - topHeight
                    
                    if offsetY > maxTop {
                        topView.top = -maxTop
                    }else if offsetY < 0 {
                        topView.top = 0
                    }else{
                        topView.top = -offsetY
                    }
                }
                
            }
            
        }
    }
    
    public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        
        // 系统默认的响应链 view
        guard let hitView = super.hitTest(point, with: event) else{
            return nil
        }
        
        // 将 point 转换到 topView 坐标系
        let pointInTopView = topView.convert(point, from: self)
        
        // 触摸在 topView 上
        if topView.point(inside: pointInTopView, with: event){
            
            if hitView != topView && hitView.isDescendant(of: topView) == true, hitView.hasInteraction() {
                // 触摸在 topView 的子控件上，直接返回，保证按钮等控件响应事件
                return hitView
            }else{
                // 不在 topView 子控件上，但在 topView 区域，转给tableView
                let index = scrollView.contentOffset.x / scrollView.width
                return subScrollViews[safe:Int(index)]
            }
            
        }
        
        return hitView
    }
    
    
}

